/**
 * @author Jason Pratt
 */

package edu.cmu.cs.stage3.alice.authoringtool.util;

import edu.cmu.cs.stage3.resourceBundle.I18n;

import java.util.Vector;

import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;

import edu.cmu.cs.stage3.alice.authoringtool.AuthoringTool;
import edu.cmu.cs.stage3.alice.authoringtool.AuthoringToolResources;
import edu.cmu.cs.stage3.alice.core.Element;
import edu.cmu.cs.stage3.alice.core.Expression;
import edu.cmu.cs.stage3.alice.core.Property;
import edu.cmu.cs.stage3.alice.core.reference.PropertyReference;
import edu.cmu.cs.stage3.swing.DialogManager;
import edu.cmu.cs.stage3.util.Criterion;
import edu.cmu.cs.stage3.util.Enumerable;
import edu.cmu.cs.stage3.util.HowMuch;
import edu.cmu.cs.stage3.util.StringObjectPair;
import edu.cmu.cs.stage3.util.criterion.InstanceOfCriterion;
import edu.cmu.cs.stage3.util.criterion.MatchesAllCriterion;
import edu.cmu.cs.stage3.util.criterion.NotCriterion;

public class PopupMenuUtilities {

 protected static java.util.HashMap recentlyUsedValues = new java.util.HashMap();

 protected static java.util.Hashtable runnablesToActionListeners = new java.util.Hashtable();

 public final static PopupItemFactory oneShotFactory = new PopupItemFactory() {
  public Object createItem( final Object o) {
   return new Runnable() {
    public void run() {
     if (o instanceof edu.cmu.cs.stage3.alice.authoringtool.util.ResponsePrototype) {
      edu.cmu.cs.stage3.alice.core.Response response = ((edu.cmu.cs.stage3.alice.authoringtool.util.ResponsePrototype)o).createNewResponse();
      edu.cmu.cs.stage3.alice.core.Response undoResponse = AuthoringToolResources.createUndoResponse( response );
      edu.cmu.cs.stage3.alice.core.Property[] properties = AuthoringToolResources.getAffectedProperties( response );
      AuthoringTool.getInstance().performOneShot( response, undoResponse, properties );
      }
     }
   };
   }
 };

 public final static javax.swing.Icon currentValueIcon = AuthoringToolResources.getIconForValue( "currentValue" );
 public final static Object NO_CURRENT_VALUE = new Object();

 protected static Criterion isNamedElement = new Criterion() {
  public boolean accept( Object o) {
   if (o instanceof edu.cmu.cs.stage3.alice.core.Element) {
    if (((edu.cmu.cs.stage3.alice.core.Element)o).name.get() != null) {
     return true;
     }
    }
   return false;
   }
 };

 //protected static NotCriterion isNotActualParameter = new NotCriterion( new InstanceOfCriterion( edu.cmu.cs.stage3.alice.core.ActualParameter.class ) );
 protected static Criterion isNotActualParameter = new Criterion() {
  public boolean accept( Object o) {
   if (o instanceof edu.cmu.cs.stage3.alice.core.Variable) {
    edu.cmu.cs.stage3.alice.core.Variable variable = (edu.cmu.cs.stage3.alice.core.Variable)o;
    if (variable.getParent() instanceof edu.cmu.cs.stage3.alice.core.response.CallToUserDefinedResponse) {
     edu.cmu.cs.stage3.alice.core.response.CallToUserDefinedResponse callToUserDefinedResponse = (edu.cmu.cs.stage3.alice.core.response.CallToUserDefinedResponse)variable.getParent();
     if (callToUserDefinedResponse.requiredActualParameters.contains( variable )) {
      return false;
     } else if (callToUserDefinedResponse.keywordActualParameters.contains( variable )) {
      return false;
      }
    } else if (variable.getParent() instanceof edu.cmu.cs.stage3.alice.core.question.userdefined.CallToUserDefinedQuestion) {
     edu.cmu.cs.stage3.alice.core.question.userdefined.CallToUserDefinedQuestion callToUserDefinedQuestion = (edu.cmu.cs.stage3.alice.core.question.userdefined.CallToUserDefinedQuestion)variable.getParent();
     if (callToUserDefinedQuestion.requiredActualParameters.contains( variable )) {
      return false;
     } else if (callToUserDefinedQuestion.keywordActualParameters.contains( variable )) {
      return false;
      }
     }
    }

   return true;
   }
 };

 protected static java.util.HashMap specialStringMap = new java.util.HashMap();

 static {
  javax.swing.JPopupMenu.setDefaultLightWeightPopupEnabled( false ); 

  specialStringMap.put( "<keyCode>", "a key" );
  specialStringMap.put( "<keyCode>", "a key" );
  specialStringMap.put( "<mouse>", "the mouse" );
  specialStringMap.put( "<onWhat>", "something" );
  specialStringMap.put( "<condition>", "something" );
  specialStringMap.put( "<variable>", "a variable" );
  specialStringMap.put( "<arrowKeys>", "the arrow keys" );
  specialStringMap.put( "<button>", "" );
  }

 public static void addRecentlyUsedValue( Class valueClass, Object value) {
  if (! recentlyUsedValues.containsKey( valueClass )) {
   recentlyUsedValues.put( valueClass, new java.util.ArrayList() );
   }
  java.util.List recentList = (java.util.List)recentlyUsedValues.get( valueClass );
  while( recentList.contains( value )) {
   recentList.remove( value );
   }
  recentList.add( 0, value );
  }

 public static void createAndShowPopupMenu( Vector structure, java.awt.Component component, int x, int y) {
  javax.swing.JPopupMenu popup = makePopupMenu( structure );
  popup.show( component, x, y );
  ensurePopupIsOnScreen( popup );
  }

 public static JPopupMenu makePopupMenu( Vector structure) {
  AliceMenuWithDelayedPopup menu = makeMenu( "", structure );
  if (menu != null){
   return menu.getPopupMenu();
   }
  return null;
  }

 public static AliceMenuWithDelayedPopup makeMenu( String title, Vector structure) {
  if (structure == null || structure.isEmpty()) {
   return null;
  } else {
   AliceMenuWithDelayedPopup menu = new AliceMenuWithDelayedPopup( title, structure );
   menu.setUI( new AliceMenuUI() );
   menu.setDelay( 0 );
   return menu;
   }
  }

 public static void populateDelayedMenu( AliceMenuWithDelayedPopup menu, Vector structure) {
  for( java.util.Enumeration enu = structure.elements(); enu.hasMoreElements();) {
   Object o = enu.nextElement();
   if (!(o instanceof StringObjectPair)) {
    throw new IllegalArgumentException( "structure must be made only of StringObjectPairs, found: " + o );
    }

   StringObjectPair pair = (StringObjectPair)o;
   String name = pair.getString();

   //hack
   if (name != null) {
    for( java.util.Iterator iter = specialStringMap.keySet().iterator(); iter.hasNext();) {
     String s = (String)iter.next();
     if (name.indexOf( s ) > -1) {
      StringBuffer sb = new StringBuffer( name );
      sb.replace( name.indexOf( s ), name.indexOf( s ) + s.length(), (String)specialStringMap.get( s ) );
      name = sb.toString();
      }
     }
    }

   Object content = pair.getObject();
   if (content instanceof DelayedBindingPopupItem) {
    content = ((DelayedBindingPopupItem)content).createItem();
    }

   javax.swing.Icon icon = null;
   if (content instanceof PopupItemWithIcon) {
    icon = ((PopupItemWithIcon)content).getIcon();
    content = ((PopupItemWithIcon)content).getItem();
    }

   if (content instanceof java.util.Vector) {
    JMenu submenu = makeMenu( name, (java.util.Vector)content );
    if (submenu != null) {
     menu.add( submenu );
     }
   } else if (content instanceof java.awt.event.ActionListener) {
    JMenuItem menuItem = makeMenuItem( name, icon );
    menuItem.addActionListener( (java.awt.event.ActionListener)content );
    menu.add( menuItem );
   } else if (content instanceof Runnable) {
    JMenuItem menuItem = makeMenuItem( name, icon );
    java.awt.event.ActionListener listener = (java.awt.event.ActionListener)runnablesToActionListeners.get( content );
    if (listener == null) {
     listener = new PopupMenuItemActionListener( (Runnable)content, menu /*MEMFIX*/ );
     //MEMFIX runnablesToActionListeners.put( content, listener );
     }
    menuItem.addActionListener( listener );
    menu.add( menuItem );
   } else if (content == javax.swing.JSeparator.class) {
    menu.addSeparator();
   } else if (content instanceof java.awt.Component) {
    menu.add( (java.awt.Component)content );
   } else if (content == null) {
    javax.swing.JLabel label = new javax.swing.JLabel( name );
    label.setBorder( javax.swing.BorderFactory.createEmptyBorder( 1, 4, 1, 4 ) );
    menu.add( label );
    }
   }
  }

 public static JMenuItem makeMenuItem( String text, javax.swing.Icon icon) {
  JMenuItem item;
  if (icon != null) {
   item = new JMenuItem( text, icon );
  } else {
   item = new JMenuItem( text );
   }
  item.setUI( new AliceMenuItemUI() );
  return item;
  }

 public static boolean isStringInStructure( String s, java.util.Vector structure) {
  for( java.util.Enumeration enu = structure.elements(); enu.hasMoreElements();) {
   StringObjectPair pair = (StringObjectPair)enu.nextElement();
   String string = pair.getString();
   Object content = pair.getObject();
   if (string == s) {
    return true;
    }
   else if (content instanceof java.util.Vector) {
    if (isStringInStructure( s, (java.util.Vector)content )) {
     return true;
     }
    }
   }
  return false;
  }

 public static boolean isObjectInStructure( Object o, java.util.Vector structure) {
  for( java.util.Enumeration enu = structure.elements(); enu.hasMoreElements();) {
   StringObjectPair pair = (StringObjectPair)enu.nextElement();
   Object content = pair.getObject();
   if (content == o) {
    return true;
    }
   else if (content instanceof java.util.Vector) {
    if (isObjectInStructure( o, (java.util.Vector)content )) {
     return true;
     }
    }
   }
  return false;
  }

 public static java.util.Vector makeFlatElementStructure( Element root, Criterion criterion, PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context, Object currentValue) {
  java.util.Vector structure = new java.util.Vector();

  edu.cmu.cs.stage3.alice.core.Element[] elements = root.search( criterion );
  //LOB for (Element element : elements)
  int t_tam = elements!=null ? elements.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   String text = AuthoringToolResources.getReprForValue( elements[i_i] ); //L ( element );
   if (context != null) {
    text = AuthoringToolResources.getNameInContext( elements[i_i], context ); //L ( element, context );
    }
   if (elements[i_i].equals( currentValue )) { //L if (element.equals( currentValue ) )
    structure.addElement( new StringObjectPair( text, new PopupItemWithIcon( factory.createItem( elements[i_i] ), currentValueIcon ) ) ); //L ...( element )
   } else {
    structure.addElement( new StringObjectPair( text, factory.createItem( elements[i_i] ) ) ); //L ( element )
    }
   }

  return structure;
  }

 public static java.util.Vector makeFlatExpressionStructure( Class valueClass, PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context, Object currentValue) {
  return makeFlatExpressionStructure( valueClass, null, factory, context, currentValue );
  }

 public static java.util.Vector makeFlatExpressionStructure( Class valueClass, Criterion criterion, PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context, Object currentValue) {
  java.util.Vector structure = new java.util.Vector();
  if (context != null) {
   edu.cmu.cs.stage3.alice.core.Expression[] expressions = context.findAccessibleExpressions( valueClass );
   //LOB for (Expression expression : expressions)
   int t_tam = expressions!=null ? expressions.length : 0;
   for (int i_i=0; i_i<t_tam; i_i++) {
    if ((criterion == null) || criterion.accept( expressions[i_i] )) { //L ( expression )
     String text = AuthoringToolResources.getReprForValue( expressions[i_i] ); //L ( expression )
     if (context != null) {
      text = AuthoringToolResources.getNameInContext( expressions[i_i], context ); //L ( expression, context )
      }
     if (expressions[i_i] instanceof edu.cmu.cs.stage3.alice.core.question.userdefined.UserDefinedQuestion) { //L if (expression instanceof...) {
      edu.cmu.cs.stage3.alice.authoringtool.util.CallToUserDefinedQuestionPrototype prototype = new edu.cmu.cs.stage3.alice.authoringtool.util.CallToUserDefinedQuestionPrototype( (edu.cmu.cs.stage3.alice.core.question.userdefined.UserDefinedQuestion)expressions[i_i] ); //L (...)expression
      if (prototype.getDesiredProperties().length > 0) {
       structure.addElement( new StringObjectPair( text, makePrototypeStructure( prototype, factory, context ) ) );
      } else {
       structure.addElement( new StringObjectPair( text, factory.createItem( prototype.createNewElement() ) ) );
      }
     } else {
      if (expressions[i_i].equals( currentValue )) { //L if (expression.equals( currentValue ) )
       structure.addElement( new StringObjectPair( text, new PopupItemWithIcon( factory.createItem( expressions[i_i] ), currentValueIcon ) ) ); //L ( expression )
      } else {
       structure.addElement( new StringObjectPair( text, factory.createItem( expressions[i_i] ) ) ); //L createItem( expression )
      }
      }
     }
   } // for (int i_i=0; i_i<t_tam; i_i++)
   }

  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ResponsePrototype and return a Runnable
  */
 public static java.util.Vector makeResponseStructure( final edu.cmu.cs.stage3.alice.core.Element element, final PopupItemFactory factory, final edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();
  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ResponsePrototype and return a Runnable
  * called by:
  * + edu.cmu.cs.stage3.alice.authoringtool.util.DnDManager: void dragDropEnd(java.awt.dnd.DragSourceDropEvent dsde)
  * + edu.cmu.cs.stage3.alice.authoringtool.editors.responseeditor.CompositeComponentResponsePanel: drop(final java.awt.dnd.DropTargetDropEvent dtde):
  *  java.util.Vector structure=edu.cmu.cs.stage3.alice.authoringtool.util.PopupMenuUtilities.makeExpressionResponseStructure(variable,factory,componentElements.getOwner())
  */
 public static java.util.Vector
     makeExpressionResponseStructure (final edu.cmu.cs.stage3.alice.core.Expression expression, final PopupItemFactory factory, final edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  System.out.println("src/edu/cmu/cs/stage3/alice/authoringtool/util/PopupMenuUtilities.java: makeExpressionResponseStructure: "+expression);
  // expression = edu.cmu.cs.stage3.alice.core.Variable[main.play.x]
  // try{String str="";System.out.println(str.charAt(3));}catch(Exception e) {e.printStackTrace();} //

  // if it's a variable, allow user to set it
  if (expression instanceof edu.cmu.cs.stage3.alice.core.Variable) {
   StringObjectPair[] known = { new StringObjectPair( "element", expression ), new StringObjectPair( "propertyName", "value" ), new StringObjectPair( "duration", new Integer( 0 ) ) };
   String[] desired = { "value" };
   edu.cmu.cs.stage3.alice.authoringtool.util.ResponsePrototype rp = new edu.cmu.cs.stage3.alice.authoringtool.util.ResponsePrototype( edu.cmu.cs.stage3.alice.core.response.PropertyAnimation.class, known, desired );
   java.util.Vector setValueStructure = edu.cmu.cs.stage3.alice.authoringtool.util.PopupMenuUtilities.makePrototypeStructure( rp, factory, context );
   if ((setValueStructure != null) && (! setValueStructure.isEmpty())) {
    structure.add( new StringObjectPair(I18n.getString("setValue"), setValueStructure ) ); // "set value"
    }
   // try{String str="";System.out.println(str.charAt(3));}catch(Exception e){e.printStackTrace();}//
   }

  // cascade to appropriate responses

  if (expression instanceof edu.cmu.cs.stage3.alice.core.Variable) {
   edu.cmu.cs.stage3.alice.core.Variable variable = (edu.cmu.cs.stage3.alice.core.Variable)expression;
   if (edu.cmu.cs.stage3.alice.core.Collection.class.isAssignableFrom( expression.getValueClass() )) {
    final edu.cmu.cs.stage3.alice.core.Collection collection = (edu.cmu.cs.stage3.alice.core.Collection)variable.value.get();
    if ((collection instanceof edu.cmu.cs.stage3.alice.core.List) || (collection instanceof edu.cmu.cs.stage3.alice.core.Array)) {
     if((collection.values.size() > 0) && edu.cmu.cs.stage3.alice.core.Model.class.isAssignableFrom( collection.valueClass.getClassValue() )) {
      if (structure.size() > 0) {
       structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
      }
      DelayedBindingPopupItem delayedBindingPopupItem = new DelayedBindingPopupItem() {
       public Object createItem() {
        java.util.Vector subStructure = new java.util.Vector();
        Object[] items = collection.values.getArrayValue();
        for( int i = 0; i < items.length; i++) {
         edu.cmu.cs.stage3.alice.core.Question question = null;
         if (collection instanceof edu.cmu.cs.stage3.alice.core.List) {
          question = new edu.cmu.cs.stage3.alice.core.question.list.ItemAtIndex();
          ((edu.cmu.cs.stage3.alice.core.question.list.ItemAtIndex)question).list.set( expression );
          ((edu.cmu.cs.stage3.alice.core.question.list.ItemAtIndex)question).index.set( new Double( i ) );
         } else if (collection instanceof edu.cmu.cs.stage3.alice.core.Array) {
          question = new edu.cmu.cs.stage3.alice.core.question.array.ItemAtIndex();
          ((edu.cmu.cs.stage3.alice.core.question.array.ItemAtIndex)question).array.set( expression );
          ((edu.cmu.cs.stage3.alice.core.question.array.ItemAtIndex)question).index.set( new Double( i ) );
         }
         java.util.Vector responseStructure = PopupMenuUtilities.makeResponseStructure( question, factory, context );
         subStructure.add( new StringObjectPair( "item" + i, responseStructure ) );
        }
        return subStructure;
       }
      };
      structure.add( new StringObjectPair( "item responses", delayedBindingPopupItem ) );
      }
     }
    }
   }

  return structure;
  }

 public static java.util.Vector makeOneShotStructure( java.util.Vector responseNames, edu.cmu.cs.stage3.alice.core.Element element, PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();
  if (responseNames != null) {
   for( java.util.Iterator iter = responseNames.iterator(); iter.hasNext();) {
    Object item = iter.next();
    if (item instanceof String) {
     String className = (String)item;
     try {
      if (className.startsWith( "edu.cmu.cs.stage3.alice.core.response.PropertyAnimation" )) {
       String propertyName = AuthoringToolResources.getSpecifier( className );
       StringObjectPair[] knownPropertyValues = new StringObjectPair[] {
         new StringObjectPair( "element", element ),
         new StringObjectPair( "propertyName", propertyName )
       };
       String[] desiredProperties = new String[] { "value" };
       edu.cmu.cs.stage3.alice.authoringtool.util.ResponsePrototype responsePrototype = new edu.cmu.cs.stage3.alice.authoringtool.util.ResponsePrototype( edu.cmu.cs.stage3.alice.core.response.PropertyAnimation.class, knownPropertyValues, desiredProperties );
       String responseName = AuthoringToolResources.getFormattedReprForValue( edu.cmu.cs.stage3.alice.core.response.PropertyAnimation.class, knownPropertyValues );
       java.util.Vector subStructure = makePrototypeStructure( responsePrototype, factory, context );
       structure.add( new StringObjectPair( responseName, subStructure ) );
      } else {
       Class responseClass = Class.forName( className );
       java.util.LinkedList known = new java.util.LinkedList();
       String format = AuthoringToolResources.getFormat( responseClass );
       edu.cmu.cs.stage3.alice.authoringtool.util.FormatTokenizer tokenizer = new edu.cmu.cs.stage3.alice.authoringtool.util.FormatTokenizer( format );
       while( tokenizer.hasMoreTokens()) {
        String token = tokenizer.nextToken();
        if (token.startsWith( "<<<" ) && token.endsWith( ">>>" )) {
         String propertyName = token.substring( token.lastIndexOf( "<" ) + 1, token.indexOf( ">" ) );
         known.add( new StringObjectPair( propertyName, element ) );
        }
       }
       StringObjectPair[] knownPropertyValues = (StringObjectPair[])known.toArray( new StringObjectPair[0] );
       String[] desiredProperties = AuthoringToolResources.getDesiredProperties( responseClass );
       edu.cmu.cs.stage3.alice.authoringtool.util.ResponsePrototype responsePrototype = new edu.cmu.cs.stage3.alice.authoringtool.util.ResponsePrototype( responseClass, knownPropertyValues, desiredProperties );
       String responseName = AuthoringToolResources.getFormattedReprForValue( responseClass, knownPropertyValues );

       if (responsePrototype.getDesiredProperties().length > 0) {
        java.util.Vector subStructure = makePrototypeStructure( responsePrototype, factory, context );
        structure.add( new StringObjectPair( responseName, subStructure ) );
       } else {
        structure.add( new StringObjectPair( responseName, factory.createItem( responsePrototype ) ) );
       }
      }
     } catch( Throwable t) {
      AuthoringTool.getInstance().showErrorDialog( "Error creating popup item.", t );
      }
    } else if (item instanceof StringObjectPair) {
     try {
      String label = ((StringObjectPair)item).getString();
      java.util.Vector subResponseNames = (java.util.Vector)((StringObjectPair)item).getObject();
      java.util.Vector subStructure = makeOneShotStructure( subResponseNames, element, factory, context );
      structure.add( new StringObjectPair( label, subStructure ) );
     } catch( Throwable t) {
      AuthoringTool.getInstance().showErrorDialog( "Error creating popup item.", t );
      }
     }
    }
   }

  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ElementPrototype and return a Runnable
  */
 public static java.util.Vector makePropertyAssignmentForUserDefinedQuestionStructure( final edu.cmu.cs.stage3.alice.core.Property property, final PopupItemFactory factory, final edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  StringObjectPair[] known = { new StringObjectPair( "element", property.getOwner() ), new StringObjectPair( "propertyName", property.getName() ) };
  String[] desired = { "value" };
  ElementPrototype ep = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.userdefined.PropertyAssignment.class, known, desired );
  java.util.Vector setValueStructure = edu.cmu.cs.stage3.alice.authoringtool.util.PopupMenuUtilities.makePrototypeStructure( ep, factory, context );
  if ((setValueStructure != null) && (! setValueStructure.isEmpty())) {
   structure.add( new StringObjectPair(I18n.getString("setValue"), setValueStructure) ); // "set value"
   }

  return structure;
  }


 // this method is overly complex, mostly following the "Big Ball Of Mud" Pattern
 // http://www.laputan.org/mud/mud.html
 /**
  * the PopupItemFactory should accept a completed ElementPrototype and rerfturn a Runnable
  */
 public static java.util.Vector makePrototypeStructure( final ElementPrototype elementPrototype, final PopupItemFactory factory, final edu.cmu.cs.stage3.alice.core.Element context){
  java.util.Vector structure = new java.util.Vector();
  final String[] desiredProperties = elementPrototype.getDesiredProperties();
  if ((desiredProperties == null) || (desiredProperties.length == 0)) {
   structure.add( new StringObjectPair( "no properties to set on " + elementPrototype.getElementClass().getName() + "; please report this bug", factory.createItem( elementPrototype ) ) ); // this should not be reached
  } else if (desiredProperties.length > 0) {
   String preRepr = elementPrototype.getElementClass().getName() + "." + desiredProperties[0];
   String propertyRepr = AuthoringToolResources.getReprForValue( preRepr );
   if (propertyRepr.equals( preRepr )) {
    propertyRepr = desiredProperties[0];
    }
   structure.add( new StringObjectPair( propertyRepr, null ) );
   //   structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
   Class preValueClass = null;
   java.util.Vector preDefaultStructure = null;
   if (edu.cmu.cs.stage3.alice.core.response.PropertyAnimation.class.isAssignableFrom( elementPrototype.getElementClass() )) {
    preDefaultStructure = getDefaultValueStructureForPropertyAnimation( elementPrototype.getKnownPropertyValues() );
    preValueClass = getValueClassForPropertyAnimation( elementPrototype.getKnownPropertyValues() );
   } else if (edu.cmu.cs.stage3.alice.core.question.userdefined.PropertyAssignment.class.isAssignableFrom( elementPrototype.getElementClass() )) {
    preDefaultStructure = getDefaultValueStructureForPropertyAnimation( elementPrototype.getKnownPropertyValues() );
    preValueClass = getValueClassForPropertyAnimation( elementPrototype.getKnownPropertyValues() );
   } else if (edu.cmu.cs.stage3.alice.core.question.list.ListBooleanQuestion.class.isAssignableFrom( elementPrototype.getElementClass() ) ||
     edu.cmu.cs.stage3.alice.core.question.list.ListNumberQuestion.class.isAssignableFrom( elementPrototype.getElementClass() ) ||
     edu.cmu.cs.stage3.alice.core.question.list.ListObjectQuestion.class.isAssignableFrom( elementPrototype.getElementClass() ) ||
     edu.cmu.cs.stage3.alice.core.response.list.ListResponse.class.isAssignableFrom( elementPrototype.getElementClass() ) )
   {
    if (desiredProperties[0].equals( "item" )) {
     preValueClass = getValueClassForList( elementPrototype.getKnownPropertyValues() );
     preDefaultStructure = getDefaultValueStructureForClass( preValueClass );
    } else if (desiredProperties[0].equals( "index" )) { // a bit hackish.
     preValueClass = edu.cmu.cs.stage3.alice.core.Element.getValueClassForPropertyNamed( elementPrototype.getElementClass(), desiredProperties[0] );
     preDefaultStructure = getDefaultValueStructureForCollectionIndexProperty( elementPrototype.getKnownPropertyValues() );
    } else {
     preValueClass = edu.cmu.cs.stage3.alice.core.Element.getValueClassForPropertyNamed( elementPrototype.getElementClass(), desiredProperties[0] );
     preDefaultStructure = getDefaultValueStructureForProperty( elementPrototype.getElementClass(), desiredProperties[0] );
     }
   } else if (edu.cmu.cs.stage3.alice.core.question.array.ArrayNumberQuestion.class.isAssignableFrom( elementPrototype.getElementClass() ) ||
     edu.cmu.cs.stage3.alice.core.question.array.ArrayObjectQuestion.class.isAssignableFrom( elementPrototype.getElementClass() ) ||
     edu.cmu.cs.stage3.alice.core.response.array.ArrayResponse.class.isAssignableFrom( elementPrototype.getElementClass() ) )
   {
    if (desiredProperties[0].equals( "item" )) {
     preValueClass = getValueClassForArray( elementPrototype.getKnownPropertyValues() );
     preDefaultStructure = getDefaultValueStructureForClass( preValueClass );
    } else if (desiredProperties[0].equals( "index" )) {
     preValueClass = edu.cmu.cs.stage3.alice.core.Element.getValueClassForPropertyNamed( elementPrototype.getElementClass(), desiredProperties[0] );
     preDefaultStructure = getDefaultValueStructureForCollectionIndexProperty( elementPrototype.getKnownPropertyValues() );
    } else {
     preValueClass = edu.cmu.cs.stage3.alice.core.Element.getValueClassForPropertyNamed( elementPrototype.getElementClass(), desiredProperties[0] );
     preDefaultStructure = getDefaultValueStructureForProperty( elementPrototype.getElementClass(), desiredProperties[0] );
     }
   } else if (elementPrototype instanceof CallToUserDefinedResponsePrototype) {
    edu.cmu.cs.stage3.alice.core.response.UserDefinedResponse actualResponse = ((CallToUserDefinedResponsePrototype)elementPrototype).getActualResponse();
    Object[] params = actualResponse.requiredFormalParameters.getArrayValue();
    //LOB for (Object param : params)
    int t_tam = params!=null ? params.length : 0;
    for (int i_i=0; i_i<t_tam; i_i++) {
     if (((edu.cmu.cs.stage3.alice.core.Variable)params[i_i]).name.getStringValue().equals( desiredProperties[0] )) { //L ( ((...)param)....)
      preValueClass = (Class)((edu.cmu.cs.stage3.alice.core.Variable)params[i_i]).valueClass.getValue(); //L ((...)param).valueClass.getValue();
      break;
      }
     }
    preDefaultStructure = getDefaultValueStructureForClass( preValueClass );
   } else if (elementPrototype instanceof CallToUserDefinedQuestionPrototype) {
    edu.cmu.cs.stage3.alice.core.question.userdefined.UserDefinedQuestion actualQuestion = ((CallToUserDefinedQuestionPrototype)elementPrototype).getActualQuestion();
    Object[] params = actualQuestion.requiredFormalParameters.getArrayValue();
    //LOB for (Object param : params)
    int t_tam = params!=null ? params.length : 0;
    for (int i_i=0; i_i<t_tam; i_i++) {
     if (((edu.cmu.cs.stage3.alice.core.Variable)params[i_i]).name.getStringValue().equals( desiredProperties[0] )) { //L ( ((...)param)...) )
      preValueClass = (Class)((edu.cmu.cs.stage3.alice.core.Variable)params[i_i]).valueClass.getValue(); //L ((...)param).valueClass.getValue();
      break;
      }
     }
    preDefaultStructure = getDefaultValueStructureForClass( preValueClass );
   } else if (edu.cmu.cs.stage3.alice.core.question.IsEqualTo.class.isAssignableFrom( elementPrototype.getElementClass()) ||
     edu.cmu.cs.stage3.alice.core.question.IsNotEqualTo.class.isAssignableFrom( elementPrototype.getElementClass())){
    preValueClass = getValueClassForComparator(elementPrototype.knownPropertyValues);
    preDefaultStructure = getDefaultValueStructureForClass( preValueClass );
   }else {
    preValueClass = edu.cmu.cs.stage3.alice.core.Element.getValueClassForPropertyNamed( elementPrototype.getElementClass(), desiredProperties[0] );
    preDefaultStructure = getDefaultValueStructureForProperty( elementPrototype.getElementClass(), desiredProperties[0] );
    }

   //   hack so we can use these in an inner class

   final Class valueClass = preValueClass;

   PopupItemFactory recursiveFactory = new PopupItemFactory() {
    public Object createItem( Object o) {
     if (desiredProperties.length == 1) { // end of the line
      return factory.createItem( elementPrototype.createCopy( new StringObjectPair( desiredProperties[0], o ) ) );
     } else { // recurse
      return makePrototypeStructure( elementPrototype.createCopy( new StringObjectPair( desiredProperties[0], o ) ), factory, context );
      }
     }
   };
   //   hack so we can use these in an inner class
   final java.util.Vector defaultStructure = processStructure( preDefaultStructure, recursiveFactory, NO_CURRENT_VALUE );
   // compute recent values
   java.util.Vector recentlyUsedStructure = new java.util.Vector();
   if (recentlyUsedValues.containsKey( preValueClass )) {
    java.util.List recentList = (java.util.List)recentlyUsedValues.get( preValueClass );
    int count = 0;
    for( java.util.Iterator iter = recentList.iterator(); iter.hasNext();) {
     Object value = iter.next();
     if (! structureContains( preDefaultStructure, value )) {
      recentlyUsedStructure.add( value );
      count++;
      }
     }
    }

   if (! defaultStructure.isEmpty()) {
    if (structure.size() > 0) {
     structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
     }
    structure.addAll( defaultStructure );
    }

   // add recent values if there are any
   if (! recentlyUsedStructure.isEmpty()) {
    if (structure.size() > 0) {
     structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
     }
    addLabelsToValueStructure( recentlyUsedStructure, elementPrototype.getElementClass(), desiredProperties[0] );
    structure.addAll( processStructure( recentlyUsedStructure, recursiveFactory, NO_CURRENT_VALUE ) );
    }

   Class elementClass = elementPrototype.getElementClass();

   // expressions
   java.util.Vector expressionStructure = makeFlatExpressionStructure( valueClass, recursiveFactory, context, NO_CURRENT_VALUE );
   if ((expressionStructure != null) && (expressionStructure.size() > 0)) {
    if (structure.size() > 0) {
     structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
     }
    structure.add( new StringObjectPair( I18n.getString("expressions"), expressionStructure ) );
    }

   // Null
   boolean nullValid = false;
   if (elementPrototype instanceof edu.cmu.cs.stage3.alice.authoringtool.util.CallToUserDefinedResponsePrototype) {
    nullValid = true;
   } else if (elementPrototype instanceof edu.cmu.cs.stage3.alice.authoringtool.util.CallToUserDefinedQuestionPrototype) {
    nullValid = true;
    }
   if (nullValid) {
    if (structure.size() > 0) {
     structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
     }
    String nullRepr = AuthoringToolResources.getReprForValue( null, elementClass, desiredProperties[0], "menuContext" );
    if (desiredProperties.length == 1) { // end of the line
     structure.add( new StringObjectPair( nullRepr, factory.createItem( elementPrototype.createCopy( new StringObjectPair( desiredProperties[0], null ) ) ) ) );
    } else { // recurse
     structure.add( new StringObjectPair( nullRepr, makePrototypeStructure( elementPrototype.createCopy( new StringObjectPair( desiredProperties[0], null ) ), factory, context ) ) );
     }
    }

   // Other...
   final PopupItemFactory otherFactory = new PopupItemFactory() {
    public Object createItem( final Object o) {
     return new Runnable() {
      public void run() {
       ((Runnable)factory.createItem( elementPrototype.createCopy( new StringObjectPair( desiredProperties[0], o ) ) )).run();
      }
     };
     }
   };
   if ((desiredProperties.length == 1) && edu.cmu.cs.stage3.alice.authoringtool.util.GUIFactory.isOtherDialogSupportedForClass( valueClass )) {
    if (structure.size() > 0) {
     structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
     }
    Runnable runnable = new Runnable() {
     public void run() {
      edu.cmu.cs.stage3.alice.authoringtool.util.GUIFactory.showOtherDialog( valueClass, null, otherFactory, context );
      }
    };
    structure.add( new StringObjectPair( I18n.getString("other")+"...", runnable ) );
    }

   // allow user to create new list
   if (edu.cmu.cs.stage3.alice.core.List.class.isAssignableFrom( valueClass ) && (desiredProperties.length == 1)) {
    if (structure.size() > 0) {
     structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
     }
    Runnable createNewListRunnable = new Runnable() {
     public void run() {
      AuthoringTool authoringTool = AuthoringTool.getInstance();
      edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty variables = context.getSandbox().variables;
      edu.cmu.cs.stage3.alice.core.Variable variable = authoringTool.showNewVariableDialog( "Create new list", context.getRoot(), true, true );
      if (variable != null) {
       if (variables != null) {
        authoringTool.getUndoRedoStack().startCompound();
        try {
         variables.getOwner().addChild( variable );
         variables.add( variable );
        } finally {
         authoringTool.getUndoRedoStack().stopCompound();
        }
       }
       ((Runnable)factory.createItem( elementPrototype.createCopy( new StringObjectPair( desiredProperties[0], variable ) ) )).run();
      }
      }
    };
    structure.add( new StringObjectPair( "create new list...", createNewListRunnable ) );
    }
   }

  return structure;
  }

 /**
  * the PopupItemFactory should accept a target value and return a Runnable
  *
  * root is used to create an Element hierarchy if needed.
  * if root is null, property.getElement().getRoot() is used.
  */
 public static java.util.Vector makePropertyStructure( final edu.cmu.cs.stage3.alice.core.Property property, final PopupItemFactory factory, boolean includeDefaults, boolean includeExpressions, boolean includeOther, edu.cmu.cs.stage3.alice.core.Element root) {
  if (root == null) {
   root = property.getOwner().getRoot();
   }
  java.util.Vector structure = new java.util.Vector();
  Class targetValueClass = edu.cmu.cs.stage3.alice.authoringtool.util.PopupMenuUtilities.getDesiredValueClass(property);
  if (edu.cmu.cs.stage3.alice.core.List.class.isAssignableFrom( targetValueClass )) { // lists are special
   edu.cmu.cs.stage3.alice.core.Element parent = property.getOwner().getParent();
   PropertyReference[] references = parent.getPropertyReferencesTo( property.getOwner(), HowMuch.INSTANCE, false );
   if ((property.getOwner() instanceof edu.cmu.cs.stage3.alice.core.question.list.ListObjectQuestion) && (references.length > 0)) {
    final Class itemValueClass = references[0].getProperty().getValueClass();
    Criterion criterion = new Criterion() {
     public boolean accept( Object o) {
      if (o instanceof edu.cmu.cs.stage3.alice.core.Variable) {
       edu.cmu.cs.stage3.alice.core.List list = (edu.cmu.cs.stage3.alice.core.List)((edu.cmu.cs.stage3.alice.core.Variable)o).getValue();
       if (list != null) {
        if (itemValueClass.isAssignableFrom( list.valueClass.getClassValue() )) {
         return true;
        }
       }
      }
      return false;
      }
    };
    structure = makeFlatExpressionStructure( targetValueClass, criterion, factory, property.getOwner(), property.get() );

   } else { // not an anonymous list question; accept all lists
    structure = makeFlatExpressionStructure( targetValueClass, factory, property.getOwner(), property.get() );

    // allow user to create new list
    if (structure.size() > 0) {
     structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
     }
    Runnable createNewListRunnable = new Runnable() {
     public void run() {
      AuthoringTool authoringTool = AuthoringTool.getInstance();
      edu.cmu.cs.stage3.alice.core.property.ObjectArrayProperty variables = property.getOwner().getSandbox().variables;
      edu.cmu.cs.stage3.alice.core.Variable variable = authoringTool.showNewVariableDialog( "Create new list", property.getOwner().getRoot(), true, true );
      if (variable != null) {
       if (variables != null) {
        variables.getOwner().addChild( variable );
        variables.add( variable );
       }
       ((Runnable)factory.createItem( variable )).run();
      }
      }
    };
    structure.add( new StringObjectPair( "create new list...", createNewListRunnable ) );
    }
  } else if (edu.cmu.cs.stage3.alice.core.Array.class.isAssignableFrom( targetValueClass )) { // arrays are special too
   edu.cmu.cs.stage3.alice.core.Element parent = property.getOwner().getParent();
   PropertyReference[] references = parent.getPropertyReferencesTo( property.getOwner(), HowMuch.INSTANCE, false );
   if ((property.getOwner() instanceof edu.cmu.cs.stage3.alice.core.question.array.ArrayObjectQuestion) && (references.length > 0)) {
    final Class itemValueClass = references[0].getProperty().getValueClass();
    Criterion criterion = new Criterion() {
     public boolean accept( Object o) {
      if (o instanceof edu.cmu.cs.stage3.alice.core.Variable) {
       edu.cmu.cs.stage3.alice.core.Array array = (edu.cmu.cs.stage3.alice.core.Array)((edu.cmu.cs.stage3.alice.core.Variable)o).getValue();
       if (array != null) {
        if (itemValueClass.isAssignableFrom( array.valueClass.getClassValue() )) {
         return true;
        }
       }
      }
      return false;
      }
    };
    structure = makeFlatExpressionStructure( targetValueClass, criterion, factory, property.getOwner(), property.get() );

   } else { // not an anonymous array question; accept all arrays
    structure = makeFlatExpressionStructure( targetValueClass, factory, property.getOwner(), property.get() );
    }
  } else {
   if (includeDefaults) {
    if (edu.cmu.cs.stage3.alice.core.Response.class.isAssignableFrom( targetValueClass )) {
    } else {
     java.util.Vector defaultStructure = getDefaultValueStructureForProperty( property );
     java.util.Vector recentlyUsedStructure = new java.util.Vector();
     if (recentlyUsedValues.containsKey( targetValueClass )) {
      java.util.List recentList = (java.util.List)recentlyUsedValues.get( targetValueClass );
      int count = 0;
      for( java.util.Iterator iter = recentList.iterator(); iter.hasNext();) {
       Object value = iter.next();
       if (! structureContains( defaultStructure, value )) {
        recentlyUsedStructure.add( value );
        count++;
       }
      }
      }

     // make sure current value is represented
     Object currentValue = property.get();
     java.util.Vector unlabeledDefaultValueStructure = getUnlabeledDefaultValueStructureForProperty( property.getOwner().getClass(), property.getName(), property ); // very hackish
     if (! (unlabeledDefaultValueStructure.contains( currentValue ) || recentlyUsedStructure.contains( currentValue ))) {
      if (! (currentValue instanceof edu.cmu.cs.stage3.alice.core.Expression)) {
       recentlyUsedStructure.add( 0, currentValue );
       }
      }

     if (structure.size() > 0) {
      structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
      }
     structure.addAll( processStructure( defaultStructure, factory, property.get() ) );
     if (! recentlyUsedStructure.isEmpty() && !property.getName().equalsIgnoreCase("keyCode")) {
      if (structure.size() > 0) {
       structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
       }
      addLabelsToValueStructure( recentlyUsedStructure, property.getOwner().getClass(), property.getName() );
      structure.addAll( processStructure( recentlyUsedStructure, factory, property.get() ) );
      }

     // Elements
     if (edu.cmu.cs.stage3.alice.core.Element.class.isAssignableFrom( targetValueClass ) || targetValueClass.isAssignableFrom( edu.cmu.cs.stage3.alice.core.Element.class )) {
      Criterion criterion;
      if ((property.getOwner() instanceof edu.cmu.cs.stage3.alice.core.Behavior) && edu.cmu.cs.stage3.alice.core.Response.class.isAssignableFrom( targetValueClass )) {
       criterion = new Criterion() { // object must be top-level response
        public boolean accept( Object o) {
         if (o instanceof edu.cmu.cs.stage3.alice.core.Response) {
          if (! (((edu.cmu.cs.stage3.alice.core.Response)o).getParent() instanceof edu.cmu.cs.stage3.alice.core.Response)) {
           return true;
          }
         }
         return false;
        }
       };
      } else if ((property.getOwner() instanceof edu.cmu.cs.stage3.alice.core.response.PropertyAnimation) && property.getName().equals( "element" )) {
       edu.cmu.cs.stage3.alice.core.response.PropertyAnimation propertyAnimation = (edu.cmu.cs.stage3.alice.core.response.PropertyAnimation)property.getOwner();
       final String propertyName = propertyAnimation.propertyName.getStringValue();
       Criterion hasProperty = new Criterion() {
        public boolean accept( Object o) {
         if (o instanceof edu.cmu.cs.stage3.alice.core.Element) {
          if (((edu.cmu.cs.stage3.alice.core.Element)o).getPropertyNamed( propertyName ) != null) {
           return true;
          }
         }
         return false;
        }
       };
       criterion = new MatchesAllCriterion( new Criterion[] { hasProperty, isNamedElement } );
      } else {
       InstanceOfCriterion instanceOf = new InstanceOfCriterion( targetValueClass );
       if (edu.cmu.cs.stage3.alice.core.Expression.class.isAssignableFrom( targetValueClass )) {
        criterion = new MatchesAllCriterion( new Criterion[] { instanceOf, isNamedElement } );
       } else {
        NotCriterion notExpression = new NotCriterion( new InstanceOfCriterion( edu.cmu.cs.stage3.alice.core.Expression.class ) );
        InAppropriateObjectArrayPropertyCriterion inAppropriateOAPCriterion = new InAppropriateObjectArrayPropertyCriterion();
        criterion = new MatchesAllCriterion( new Criterion[] { instanceOf, notExpression, isNamedElement, inAppropriateOAPCriterion } );
       }
      }
      edu.cmu.cs.stage3.alice.core.Element[] elements = root.search( criterion );

      if ((structure.size() > 0) && (elements.length > 0)) {
       structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
       }
      if (elements.length < 10) {
       structure.addAll( makeFlatElementStructure( root, criterion, factory, root, property.get() ) );
       }

      }
     }
    }
   if (includeExpressions) {

    java.util.Vector expressionStructure = makeFlatExpressionStructure( targetValueClass, factory, property.getOwner(), property.get() );
    if ((expressionStructure != null) && (expressionStructure.size() > 0)) {
     if (structure.size() > 0) {
      structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
      }
     structure.add( new StringObjectPair( I18n.getString("expressions"), expressionStructure ) );
    } else if (structure.size() == 0) {
     javax.swing.JLabel label = new javax.swing.JLabel( "no expressions for this type" );
     label.setForeground( java.awt.Color.gray );
     label.setBorder( javax.swing.BorderFactory.createEmptyBorder( 2, 8, 2, 2 ) );
     structure.add( new StringObjectPair( "", label ) );
     }
    }

   if (Boolean.class.isAssignableFrom( targetValueClass ) && includeExpressions) {
    java.util.Vector booleanLogicStructure = makeBooleanLogicStructure( property.get(), factory, property.getOwner() );
    if (booleanLogicStructure!= null){
     if (structure.size() > 0) {
      structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
      }
     structure.add( new StringObjectPair( "logic", booleanLogicStructure ) );
     }
    }

   if (Number.class.isAssignableFrom( targetValueClass ) && includeExpressions) {
    java.util.Vector mathStructure = makeCommonMathQuestionStructure( property.get(), factory, property.getOwner() );
    if (mathStructure != null){
     if (structure.size() > 0) {
      structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
      }
     structure.add( new StringObjectPair( I18n.getString("math"), mathStructure ) );
     }
    }

   if (includeOther && edu.cmu.cs.stage3.alice.authoringtool.util.GUIFactory.isOtherDialogSupportedForClass( targetValueClass )) {
    if (structure.size() > 0) {
     structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
     }
    final Class finalOtherValueClass = targetValueClass;
    Runnable runnable = new Runnable() {
     public void run() {
      edu.cmu.cs.stage3.alice.authoringtool.util.GUIFactory.showOtherPropertyDialog( property, factory, null, finalOtherValueClass );
      }
    };
    structure.add( new StringObjectPair( I18n.getString("other")+"...", runnable ) );
    }
   }

  if (structure.size() == 0) {
   javax.swing.JLabel label = new javax.swing.JLabel( "nothing to choose" );
   label.setForeground( java.awt.Color.gray );
   label.setBorder( javax.swing.BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
   structure.add( new StringObjectPair( "", label ) );
   }

  return structure;
  }

 public static java.util.Vector makeListQuestionStructure( final edu.cmu.cs.stage3.alice.core.Variable listVariable, final PopupItemFactory factory, Class returnValueClass, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  edu.cmu.cs.stage3.alice.core.List list = (edu.cmu.cs.stage3.alice.core.List)listVariable.getValue();
  edu.cmu.cs.stage3.alice.authoringtool.util.PopupItemFactory prototypeToItemFactory = new edu.cmu.cs.stage3.alice.authoringtool.util.PopupItemFactory() {
   public Object createItem( final Object object) {
    edu.cmu.cs.stage3.alice.authoringtool.util.ElementPrototype ep = (edu.cmu.cs.stage3.alice.authoringtool.util.ElementPrototype)object;
    return factory.createItem( ep.createNewElement() );
    }
  };

  if (returnValueClass.isAssignableFrom( list.valueClass.getClassValue() )) {
   Runnable firstItemRunnable = new Runnable() { public void run() {
    edu.cmu.cs.stage3.alice.core.question.list.ItemAtBeginning itemAtBeginning = new edu.cmu.cs.stage3.alice.core.question.list.ItemAtBeginning();
    itemAtBeginning.list.set( listVariable );
    ((Runnable)factory.createItem( itemAtBeginning )).run();
   } };
   Runnable lastItemRunnable = new Runnable() { public void run() {
    edu.cmu.cs.stage3.alice.core.question.list.ItemAtEnd itemAtEnd = new edu.cmu.cs.stage3.alice.core.question.list.ItemAtEnd();
    itemAtEnd.list.set( listVariable );
    ((Runnable)factory.createItem( itemAtEnd )).run();
   } };
   Runnable randomItemRunnable = new Runnable() { public void run() {
    edu.cmu.cs.stage3.alice.core.question.list.ItemAtRandomIndex itemAtRandomIndex = new edu.cmu.cs.stage3.alice.core.question.list.ItemAtRandomIndex();
    itemAtRandomIndex.list.set( listVariable );
    ((Runnable)factory.createItem( itemAtRandomIndex )).run();
   } };

   StringObjectPair[] known = new StringObjectPair[] { new StringObjectPair( "list", listVariable ) };
   String[] desired = new String[] { "index" };
   ElementPrototype ithPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.list.ItemAtIndex.class, known, desired );
   java.util.Vector ithStructure = makePrototypeStructure( ithPrototype, prototypeToItemFactory, context );

   structure.add( new StringObjectPair( "first item from list", firstItemRunnable ) );
   structure.add( new StringObjectPair( "last item from list", lastItemRunnable ) );
   structure.add( new StringObjectPair( "random item from list", randomItemRunnable ) );
   structure.add( new StringObjectPair( "ith item from list", ithStructure ) );
   }
  if (returnValueClass.isAssignableFrom( Boolean.class )) {
   Runnable isEmptyRunnable = new Runnable() { public void run() {
    edu.cmu.cs.stage3.alice.core.question.list.IsEmpty isEmpty = new edu.cmu.cs.stage3.alice.core.question.list.IsEmpty();
    isEmpty.list.set( listVariable );
    ((Runnable)factory.createItem( isEmpty )).run();
   } };

   StringObjectPair[] known = new StringObjectPair[] { new StringObjectPair( "list", listVariable ) };
   String[] desired = new String[] { "item" };
   ElementPrototype containsPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.list.Contains.class, known, desired );
   java.util.Vector containsStructure = makePrototypeStructure( containsPrototype, prototypeToItemFactory, context );

   if (structure.size() > 0) {
    structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
    }
   structure.add( new StringObjectPair( "is list empty", isEmptyRunnable ) );
   structure.add( new StringObjectPair( "list contains", containsStructure ) );
   }

  if (returnValueClass.isAssignableFrom( Number.class )) {
   Runnable sizeRunnable = new Runnable() { public void run() {
    edu.cmu.cs.stage3.alice.core.question.list.Size size = new edu.cmu.cs.stage3.alice.core.question.list.Size();
    size.list.set( listVariable );
    ((Runnable)factory.createItem( size )).run();
   } };

   StringObjectPair[] known = new StringObjectPair[] { new StringObjectPair( "list", listVariable ) };
   String[] desired = new String[] { "item" };

   ElementPrototype firstIndexOfItemPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.list.FirstIndexOfItem.class, known, desired );
   java.util.Vector firstIndexOfItemStructure = makePrototypeStructure( firstIndexOfItemPrototype, prototypeToItemFactory, context );

   ElementPrototype lastIndexOfItemPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.list.LastIndexOfItem.class, known, desired );
   java.util.Vector lastIndexOfItemStructure = makePrototypeStructure( lastIndexOfItemPrototype, prototypeToItemFactory, context );

   if (structure.size() > 0) {
    structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
    }
   structure.add( new StringObjectPair( "size of list", sizeRunnable ) );
   structure.add( new StringObjectPair( "first index of", firstIndexOfItemStructure ) );
   structure.add( new StringObjectPair( "last index of", lastIndexOfItemStructure ) );
   }

  return structure;
  }

 public static java.util.Vector makeArrayQuestionStructure( final edu.cmu.cs.stage3.alice.core.Variable arrayVariable, final PopupItemFactory factory, Class returnValueClass, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  edu.cmu.cs.stage3.alice.core.Array array = (edu.cmu.cs.stage3.alice.core.Array)arrayVariable.getValue();

  edu.cmu.cs.stage3.alice.authoringtool.util.PopupItemFactory prototypeToItemFactory = new edu.cmu.cs.stage3.alice.authoringtool.util.PopupItemFactory() {
   public Object createItem( final Object object) {
    edu.cmu.cs.stage3.alice.authoringtool.util.ElementPrototype ep = (edu.cmu.cs.stage3.alice.authoringtool.util.ElementPrototype)object;
    return factory.createItem( ep.createNewElement() );
    }
  };

  if (returnValueClass.isAssignableFrom( array.valueClass.getClassValue() )) {
   StringObjectPair[] known = new StringObjectPair[] { new StringObjectPair( "array", arrayVariable ) };
   String[] desired = new String[] { "index" };
   ElementPrototype ithPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.array.ItemAtIndex.class, known, desired );
   java.util.Vector ithStructure = makePrototypeStructure( ithPrototype, prototypeToItemFactory, context );

   structure.add( new StringObjectPair( "ith item from array", ithStructure ) );
   }

  if (returnValueClass.isAssignableFrom( Number.class )) {
   Runnable sizeRunnable = new Runnable() { public void run() {
    edu.cmu.cs.stage3.alice.core.question.array.Size size = new edu.cmu.cs.stage3.alice.core.question.array.Size();
    size.array.set( arrayVariable );
    ((Runnable)factory.createItem( size )).run();
   } };

   if (structure.size() > 0) {
    structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
    }
   structure.add( new StringObjectPair( "size of array", sizeRunnable ) );
   }

  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ElementPrototype and return a Runnable
  */
 public static java.util.Vector makeCommonMathQuestionStructure( final Object firstOperand, final PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  if (firstOperand instanceof Number) {
   //accept
  } else if ((firstOperand instanceof edu.cmu.cs.stage3.alice.core.Expression) && Number.class.isAssignableFrom( ((edu.cmu.cs.stage3.alice.core.Expression)firstOperand).getValueClass() )) {
   //accept
  } else if (firstOperand == null) {
   //accept
  } else {
   throw new IllegalArgumentException( "firstOperand must represent a Number" );
   }

  String firstOperandRepr = AuthoringToolResources.getReprForValue( firstOperand, false );

  StringObjectPair[] known = new StringObjectPair[] { new StringObjectPair( "a", firstOperand ) };
  String[] desired = new String[] { "b" };

  ElementPrototype addPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.NumberAddition.class, known, desired );
  java.util.Vector addStructure = makePrototypeStructure( addPrototype, factory, context );
  ElementPrototype subtractPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.NumberSubtraction.class, known, desired );
  java.util.Vector subtractStructure = makePrototypeStructure( subtractPrototype, factory, context );
  ElementPrototype multiplyPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.NumberMultiplication.class, known, desired );
  java.util.Vector multiplyStructure = makePrototypeStructure( multiplyPrototype, factory, context );
  ElementPrototype dividePrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.NumberDivision.class, known, desired );
  java.util.Vector divideStructure = makePrototypeStructure( dividePrototype, factory, context );

  structure.add( new StringObjectPair( firstOperandRepr + " +", addStructure ) );
  structure.add( new StringObjectPair( firstOperandRepr + " -", subtractStructure ) );
  structure.add( new StringObjectPair( firstOperandRepr + " *", multiplyStructure ) );
  structure.add( new StringObjectPair( firstOperandRepr + " /", divideStructure ) );

  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ElementPrototype and return a Runnable
  */
 public static java.util.Vector makeBooleanLogicStructure( final Object firstOperand, final PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();
  if (firstOperand instanceof Boolean) {
   //accept
  } else if ((firstOperand instanceof edu.cmu.cs.stage3.alice.core.Expression) && Boolean.class.isAssignableFrom( ((edu.cmu.cs.stage3.alice.core.Expression)firstOperand).getValueClass() )) {
   //accept
  } else if (firstOperand == null) {
   return null;
  } else {
   throw new IllegalArgumentException( "firstOperand must represent a Boolean" );
   }

  String firstOperandRepr = AuthoringToolResources.getReprForValue( firstOperand, false );

  StringObjectPair[] known = new StringObjectPair[] { new StringObjectPair( "a", firstOperand ) };
  String[] desired = new String[] { "b" };

  ElementPrototype andPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.And.class, known, desired );
  java.util.Vector andStructure = makePrototypeStructure( andPrototype, factory, context );
  ElementPrototype orPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.Or.class, known, desired );
  java.util.Vector orStructure = makePrototypeStructure( orPrototype, factory, context );
  ElementPrototype notPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.Not.class, known, new String[0] );
  Object notItem = factory.createItem( notPrototype );
  ElementPrototype equalPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.IsEqualTo.class, known, desired );
  java.util.Vector equalStructure = makePrototypeStructure( equalPrototype, factory, context );
  ElementPrototype notEqualPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.IsNotEqualTo.class, known, desired );
  java.util.Vector notEqualStructure = makePrototypeStructure( notEqualPrototype, factory, context );

  structure.add( new StringObjectPair( firstOperandRepr + " and", andStructure ) );
  structure.add( new StringObjectPair( firstOperandRepr + " or", orStructure ) );
  structure.add( new StringObjectPair( "not " + firstOperandRepr, notItem ) );
  structure.add( new StringObjectPair( "Separator", javax.swing.JSeparator.class ) );
  structure.add( new StringObjectPair( firstOperandRepr + " ==", equalStructure ) );
  structure.add( new StringObjectPair( firstOperandRepr + " !=", notEqualStructure ) );

  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ElementPrototype and return a Runnable
  */
 public static java.util.Vector makeComparatorStructure( final Object firstOperand, final PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  String firstOperandRepr = AuthoringToolResources.getReprForValue( firstOperand, false );

  StringObjectPair[] known = new StringObjectPair[] { new StringObjectPair( "a", firstOperand ) };
  String[] desired = new String[] { "b" };
  ElementPrototype equalPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.IsEqualTo.class, known, desired );
  java.util.Vector equalStructure = makePrototypeStructure( equalPrototype, factory, context );
  ElementPrototype notEqualPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.IsNotEqualTo.class, known, desired );
  java.util.Vector notEqualStructure = makePrototypeStructure( notEqualPrototype, factory, context );

  structure.add( new StringObjectPair( firstOperandRepr + " ==", equalStructure ) );
  structure.add( new StringObjectPair( firstOperandRepr + " !=", notEqualStructure ) );

  if ((firstOperand instanceof Number) || ((firstOperand instanceof edu.cmu.cs.stage3.alice.core.Expression) && Number.class.isAssignableFrom( ((edu.cmu.cs.stage3.alice.core.Expression)firstOperand).getValueClass() ))) {

   ElementPrototype lessThanPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.NumberIsLessThan.class, known, desired );
   java.util.Vector lessThanStructure = makePrototypeStructure( lessThanPrototype, factory, context );
   ElementPrototype greaterThanPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.NumberIsGreaterThan.class, known, desired );
   java.util.Vector greaterThanStructure = makePrototypeStructure( greaterThanPrototype, factory, context );
   ElementPrototype lessThanOrEqualPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.NumberIsLessThanOrEqualTo.class, known, desired );
   java.util.Vector lessThanOrEqualStructure = makePrototypeStructure( lessThanOrEqualPrototype, factory, context );
   ElementPrototype greaterThanOrEqualPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.NumberIsGreaterThanOrEqualTo.class, known, desired );
   java.util.Vector greaterThanOrEqualStructure = makePrototypeStructure( greaterThanOrEqualPrototype, factory, context );

   structure.add( new StringObjectPair( firstOperandRepr + " <", lessThanStructure ) );
   structure.add( new StringObjectPair( firstOperandRepr + " >", greaterThanStructure ) );
   structure.add( new StringObjectPair( firstOperandRepr + " <=", lessThanOrEqualStructure ) );
   structure.add( new StringObjectPair( firstOperandRepr + " >=", greaterThanOrEqualStructure ) );
   }

  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ElementPrototype and return a Runnable
  */
 public static java.util.Vector makeResponsePrintStructure( final PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  final StringObjectPair[] known = new StringObjectPair[0];

  Runnable textStringRunnable = new Runnable() {
   public void run() {
    ElementPrototype elementPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.response.Print.class, known, new String[] { "text" } );
    String text = DialogManager.showInputDialog(I18n.getString("enterTextToPrint")+":", I18n.getString("enterTextString"), javax.swing.JOptionPane.PLAIN_MESSAGE );
    if (text != null) {
     ((Runnable)factory.createItem( elementPrototype.createCopy( new StringObjectPair( "text", text ) ) )).run();
     }
    }
  };
  structure.add( new StringObjectPair( I18n.getString("textString")+"...", textStringRunnable ) );

  ElementPrototype elementPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.response.Print.class, known, new String[] { "object" } );
  structure.add( new StringObjectPair(I18n.getString("object"), PopupMenuUtilities.makePrototypeStructure( elementPrototype, factory, context ) ) );

  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ElementPrototype and return a Runnable
  */
 public static java.util.Vector makeQuestionPrintStructure( final PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  final StringObjectPair[] known = new StringObjectPair[0];

  Runnable textStringRunnable = new Runnable() {
   public void run() {
    ElementPrototype elementPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.userdefined.Print.class, known, new String[] { "text" } );
    String text = DialogManager.showInputDialog(I18n.getString("enterTextToPrint")+":", I18n.getString("enterTextString"), javax.swing.JOptionPane.PLAIN_MESSAGE );
    if (text != null) {
     ((Runnable)factory.createItem( elementPrototype.createCopy( new StringObjectPair( "text", text ) ) )).run();
     }
    }
  };
  structure.add( new StringObjectPair( "text string...", textStringRunnable ) );

  ElementPrototype elementPrototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.userdefined.Print.class, known, new String[] { "object" } );
  structure.add( new StringObjectPair( "object", PopupMenuUtilities.makePrototypeStructure( elementPrototype, factory, context ) ) );

  return structure;
  }

 /**
  * the PopupItemFactory should accept a completed ElementPrototype and return a Runnable
  */
 public static java.util.Vector makePropertyValueStructure( final edu.cmu.cs.stage3.alice.core.Element element, Class valueClass, final PopupItemFactory factory, edu.cmu.cs.stage3.alice.core.Element context) {
  java.util.Vector structure = new java.util.Vector();

  Class elementClass = null;
  if (element instanceof edu.cmu.cs.stage3.alice.core.Expression) {
   elementClass = ((edu.cmu.cs.stage3.alice.core.Expression)element).getValueClass();
  } else {
   elementClass = element.getClass();
   }

  StringObjectPair[] known = new StringObjectPair[] { new StringObjectPair( "element", element ) };
  String[] desired = new String[] { "propertyName" };
  ElementPrototype prototype = new ElementPrototype( edu.cmu.cs.stage3.alice.core.question.PropertyValue.class, known, desired );

  String[] propertyNames = getPropertyNames( elementClass, valueClass );
  String prefix = AuthoringToolResources.getReprForValue( element, false ) + ".";
  for( int i = 0; i < propertyNames.length; i++) {
   if ((! propertyNames[i].equals( "visualization" )) && (! propertyNames[i].equals( "isFirstClass" ))) { // HACK suppression
    String propertyName = AuthoringToolResources.getReprForValue( propertyNames[i], false );
    structure.add( new StringObjectPair( prefix + propertyName, factory.createItem( prototype.createCopy( new StringObjectPair( "propertyName", propertyName ) ) ) ) );
    }
   }

  return structure;
  }

 // HACK until this method is on Element
 private static String[] getPropertyNames( Class elementClass, Class valueClass) {
  try {
   edu.cmu.cs.stage3.alice.core.Element element = (edu.cmu.cs.stage3.alice.core.Element)elementClass.newInstance();
   edu.cmu.cs.stage3.alice.core.Property[] properties = element.getProperties();
   java.util.Vector propertyNames = new java.util.Vector();
   //LOB for (Property propertie : properties)
   int t_tam = properties!=null ? properties.length : 0;
   for (int i_i=0; i_i<t_tam; i_i++) {
    if (valueClass.isAssignableFrom( properties[i_i].getValueClass() )) { //L ( propertie.getValueClass() )
     propertyNames.add( properties[i_i].getName() ); //L propertyNames.add( propertie.getName() );
     }
    }
   return (String[])propertyNames.toArray( new String[0] );
  } catch( InstantiationException ie) {
   return null;
  } catch( IllegalAccessException iae) {
   return null;
   }
  }

 public static java.util.Vector getDefaultValueStructureForProperty( Class elementClass, String propertyName) {
  return getDefaultValueStructureForProperty( elementClass, propertyName, null );
  }

 public static java.util.Vector getDefaultValueStructureForProperty( edu.cmu.cs.stage3.alice.core.Property property) {
  return getDefaultValueStructureForProperty( property.getOwner().getClass(), property.getName(), property );
  }

 // property may be null if it is not available. if it is available, though, it will be used to derive the value class.
 public static java.util.Vector getDefaultValueStructureForProperty( Class elementClass, String propertyName, edu.cmu.cs.stage3.alice.core.Property property) {
  java.util.Vector structure = new java.util.Vector( getUnlabeledDefaultValueStructureForProperty( elementClass, propertyName, property ) );
  addLabelsToValueStructure( structure, elementClass, propertyName );
  return structure;
  }

 // property may be null if it is not available. if it is available, though, it will be used to derive the value class.
 public static java.util.Vector getUnlabeledDefaultValueStructureForProperty( Class elementClass, String propertyName, edu.cmu.cs.stage3.alice.core.Property property) {
  if (property != null) {
   if ((property.getOwner() instanceof edu.cmu.cs.stage3.alice.core.response.PropertyAnimation) && property.getName().equals( "value" )) {
    edu.cmu.cs.stage3.alice.core.response.PropertyAnimation propertyAnimation = (edu.cmu.cs.stage3.alice.core.response.PropertyAnimation)property.getOwner();
    elementClass = propertyAnimation.element.getElementValue().getClass();
    if (propertyAnimation.element.getElementValue()instanceof edu.cmu.cs.stage3.alice.core.Variable){
     edu.cmu.cs.stage3.alice.core.Variable var = (edu.cmu.cs.stage3.alice.core.Variable)propertyAnimation.element.getElementValue();
     elementClass = var.getValueClass();
     }
    propertyName = propertyAnimation.propertyName.getStringValue();

   } else if ((property.getOwner() instanceof edu.cmu.cs.stage3.alice.core.question.userdefined.PropertyAssignment) && property.getName().equals( "value" )) {
    edu.cmu.cs.stage3.alice.core.question.userdefined.PropertyAssignment propertyAssignment = (edu.cmu.cs.stage3.alice.core.question.userdefined.PropertyAssignment)property.getOwner();
    elementClass = propertyAssignment.element.getElementValue().getClass();
    if (propertyAssignment.element.getElementValue() instanceof edu.cmu.cs.stage3.alice.core.Variable){
     edu.cmu.cs.stage3.alice.core.Variable var = (edu.cmu.cs.stage3.alice.core.Variable)propertyAssignment.element.getElementValue();
     elementClass = var.getValueClass();
     }
    propertyName = propertyAssignment.propertyName.getStringValue();
    }
   }
  java.util.Vector structure = AuthoringToolResources.getDefaultPropertyValues( elementClass, propertyName );
  if (structure == null) {
   structure = new java.util.Vector();
   }
  if (structure.size() < 1) {
   Class valueClass;
   if (property != null) {
    if ((property.getOwner() instanceof edu.cmu.cs.stage3.alice.core.question.BinaryObjectResultingInBooleanQuestion) && (property.getName().equals( "a" ) || property.getName().equals( "b" ))) {
     Object otherValue;
     if (property.getName().equals( "a" )) {
      otherValue = ((edu.cmu.cs.stage3.alice.core.question.BinaryObjectResultingInBooleanQuestion)property.getOwner()).b.get();
     } else {
      otherValue = ((edu.cmu.cs.stage3.alice.core.question.BinaryObjectResultingInBooleanQuestion)property.getOwner()).a.get();
      }

     if (otherValue instanceof edu.cmu.cs.stage3.alice.core.Expression) {
      valueClass = ((edu.cmu.cs.stage3.alice.core.Expression)otherValue).getValueClass();
     } else if (otherValue != null) {
      valueClass = otherValue.getClass();
     } else {
      valueClass = property.getValueClass();
      }
    } else {
     valueClass = property.getValueClass();
     }
   } else {
    valueClass = edu.cmu.cs.stage3.alice.core.Element.getValueClassForPropertyNamed( elementClass, propertyName );
    }
   structure.addAll( getUnlabeledDefaultValueStructureForClass( valueClass ) );
   }

  return structure;
  }

 public static java.util.Vector getDefaultValueStructureForCollectionIndexProperty( StringObjectPair[] knownPropertyValues) {
  Object collection = null;
  //LOB for (StringObjectPair knownPropertyValue : knownPropertyValues)
  int t_tam = knownPropertyValues!=null ? knownPropertyValues.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   if (knownPropertyValues[i_i].getString().equals( "list" )) { //L if (knownPropertyValue.getString().equals( "list" ) )
    collection = knownPropertyValues[i_i].getObject(); //L collection = knownPropertyValue.getObject();
    break;
   } else if (knownPropertyValues[i_i].getString().equals( "array" )) { //L if (knownPropertyValue.getString().equals( "array" ) )
    collection = knownPropertyValues[i_i].getObject(); //L collection = knownPropertyValue.getObject();
    break;
    }
   }

  edu.cmu.cs.stage3.alice.core.Collection realCollection = null;
  if (collection instanceof edu.cmu.cs.stage3.alice.core.Variable) {
   realCollection = (edu.cmu.cs.stage3.alice.core.Collection)((edu.cmu.cs.stage3.alice.core.Variable)collection).getValue();
  } else if (collection instanceof edu.cmu.cs.stage3.alice.core.Collection) {
   realCollection = (edu.cmu.cs.stage3.alice.core.Collection)collection;
   }

  java.util.Vector structure = new java.util.Vector();
  if (realCollection != null) {
   int size = realCollection.values.size();
   for( int i = 0; (i < size) && (i < 10); i++) {
    structure.add( new StringObjectPair( Integer.toString( i ), new Double( (double)i ) ) );
    }
   }

  if (structure.size() < 1) {
   structure.add( new StringObjectPair( "0", new Double( 0.0 ) ) );
   }

  return structure;
  }

 public static java.util.Vector getDefaultValueStructureForClass( Class valueClass) {
  java.util.Vector structure = getUnlabeledDefaultValueStructureForClass( valueClass );
  addLabelsToValueStructure( structure );
  return structure;
  }

 // Options to initiate variable
 public static java.util.Vector getUnlabeledDefaultValueStructureForClass (Class valueClass) {
  // try{String str=""; System.out.println(str.charAt(3));}catch(Exception e) {e.printStackTrace();}
  java.util.Vector structure = new java.util.Vector();
  if (Boolean.class.isAssignableFrom( valueClass )) {
   structure.add( Boolean.TRUE );
   structure.add( Boolean.FALSE );
  } else if (Number.class.isAssignableFrom( valueClass )) {
   structure.add( new Double( 0 ) );
   structure.add( new Double( .25 ) );
   structure.add( new Double( .5 ) );
   structure.add( new Double( 1.0 ) );
   structure.add( new Double( 2.0 ) );
  } else if (Enumerable.class.isAssignableFrom( valueClass )) {
   Enumerable[] enuItems = Enumerable.getItems( valueClass );
   //LOB for (Enumerable enuItem : enuItems)
   int t_tam = enuItems!=null ? enuItems.length : 0;
   for (int i_i=0; i_i<t_tam; i_i++) {
    structure.add( enuItems[i_i] ); //L structure.add( enuItem );
    }
  } else if (edu.cmu.cs.stage3.alice.core.Style.class.isAssignableFrom( valueClass )) {
   structure.add( edu.cmu.cs.stage3.alice.core.style.TraditionalAnimationStyle.BEGIN_AND_END_GENTLY );
   structure.add( edu.cmu.cs.stage3.alice.core.style.TraditionalAnimationStyle.BEGIN_GENTLY_AND_END_ABRUPTLY );
   structure.add( edu.cmu.cs.stage3.alice.core.style.TraditionalAnimationStyle.BEGIN_ABRUPTLY_AND_END_GENTLY );
   structure.add( edu.cmu.cs.stage3.alice.core.style.TraditionalAnimationStyle.BEGIN_AND_END_ABRUPTLY);
  } else if (String.class.isAssignableFrom( valueClass )) {
   structure.add(I18n.getString("defaultString"));
   }
  return structure;
  }

 // have to special-case PropertyAnimations
 private static java.util.Vector getDefaultValueStructureForPropertyAnimation( StringObjectPair[] knownPropertyValues) {
  java.util.Vector structure = new java.util.Vector();
  edu.cmu.cs.stage3.alice.core.Element element = null;
  String propertyName = null;
  //LOB for (StringObjectPair knownPropertyValue : knownPropertyValues)
  int t_tam = knownPropertyValues!=null ? knownPropertyValues.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   if (knownPropertyValues[i_i].getString().equals( "element" )) { //L if (knownPropertyValue.getString().equals( "element" ) )
    element = (edu.cmu.cs.stage3.alice.core.Element)knownPropertyValues[i_i].getObject(); //L (...)knownPropertyValue.getObject();
    break;
    }
  } // for (int i_i=0; i_i<t_tam; i_i++)
  //LOB for (StringObjectPair knownPropertyValue : knownPropertyValues)
  t_tam = knownPropertyValues!=null ? knownPropertyValues.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   if (knownPropertyValues[i_i].getString().equals( "propertyName" )) { //L if (knownPropertyValue.getString().equals( "propertyName" ) )
    propertyName = (String)knownPropertyValues[i_i].getObject(); //L (String)knownPropertyValue.getObject();
    break;
    }
   }
  if ((element != null) && (propertyName != null)) {
   Class elementClass = element.getClass();
   if (element instanceof edu.cmu.cs.stage3.alice.core.Expression) {
    elementClass = ((edu.cmu.cs.stage3.alice.core.Expression)element).getValueClass();
    }
   structure = getDefaultValueStructureForProperty( elementClass, propertyName, element.getPropertyNamed( propertyName ) );
   }

  return structure;
  }

 private static void addLabelsToValueStructure( java.util.Vector structure) {
  for( java.util.ListIterator iter = structure.listIterator(); iter.hasNext();) {
   Object item = iter.next();
   if (item instanceof StringObjectPair) {
    StringObjectPair sop = (StringObjectPair)item;
    if (sop.getObject() instanceof java.util.Vector) {
     addLabelsToValueStructure( (java.util.Vector)sop.getObject() );
     }
   } else if (item instanceof java.util.Vector) {
    AuthoringTool.getInstance().showErrorDialog( "Unexpected Vector found while processing value structure", null );
   } else {
    String text = AuthoringToolResources.getReprForValue( item );
    iter.set( new StringObjectPair( text, item ) );
    }
   }
  }

 private static void addLabelsToValueStructure( java.util.Vector structure, Class elementClass, String propertyName) {
  for( java.util.ListIterator iter = structure.listIterator(); iter.hasNext();) {
   Object item = iter.next();
   if (item instanceof StringObjectPair) {
    StringObjectPair sop = (StringObjectPair)item;
    if (sop.getObject() instanceof java.util.Vector) {
     addLabelsToValueStructure( (java.util.Vector)sop.getObject(), elementClass, propertyName );
     }
   } else if (item instanceof java.util.Vector) {
    AuthoringTool.getInstance().showErrorDialog( "Unexpected Vector found while processing value structure", null );
   } else {
    String text = AuthoringToolResources.getReprForValue( item, elementClass, propertyName, "menuContext" );
    iter.set( new StringObjectPair( text, item ) );
    }
   }
  }

 private static java.util.Vector processStructure( java.util.Vector structure, edu.cmu.cs.stage3.alice.authoringtool.util.PopupItemFactory factory, Object currentValue) {
  java.util.Vector processed = new java.util.Vector();
  for( java.util.Iterator iter = structure.iterator(); iter.hasNext();) {
   Object item = iter.next();
   if (item instanceof StringObjectPair) {
    StringObjectPair sop = (StringObjectPair)item;
    if (sop.getObject() instanceof java.util.Vector) {
     processed.add( new StringObjectPair( sop.getString(), processStructure( (java.util.Vector)sop.getObject(), factory, currentValue ) ) );
    } else {
     if (((currentValue == null) && (sop.getObject() == null)) || ((currentValue != null) && currentValue.equals( sop.getObject() ))) {
      processed.add( new StringObjectPair( sop.getString(), new PopupItemWithIcon( factory.createItem( sop.getObject() ), currentValueIcon ) ) );
     } else {
      processed.add( new StringObjectPair( sop.getString(), factory.createItem( sop.getObject() ) ) );
      }
     }
   } else {
    AuthoringTool.getInstance().showErrorDialog( "Unexpected Vector found while processing value structure", null );
    }
   }
  return processed;
  }

 public static boolean structureContains( java.util.Vector structure, Object value) {
  for( java.util.Iterator iter = structure.iterator(); iter.hasNext();) {
   Object item = iter.next();
   if (item instanceof StringObjectPair) {
    StringObjectPair sop = (StringObjectPair)item;
    if (sop.getObject() instanceof java.util.Vector) {
     if (structureContains( (java.util.Vector)sop.getObject(), value )) {
      return true;
      }
    } else if (sop.getObject() == null) {
     if (value == null) {
      return true;
      }
    } else {
     if (sop.getObject().equals( value )) {
      return true;
      }
     }
    }
   }
  return false;
  }

 // have to special-case PropertyAnimations
 private static Class getValueClassForPropertyAnimation( StringObjectPair[] knownPropertyValues) {
  Class valueClass = null;
  edu.cmu.cs.stage3.alice.core.Element element = null;
  String propertyName = null;
  //LOB for (StringObjectPair knownPropertyValue : knownPropertyValues)
  int t_tam = knownPropertyValues!=null ? knownPropertyValues.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   if (knownPropertyValues[i_i].getString().equals( "element" )) { //L if (knownPropertyValue.getString().equals( "element" ) )
    element = (edu.cmu.cs.stage3.alice.core.Element)knownPropertyValues[i_i].getObject(); //L (...)knownPropertyValue.getObject();
    break;
    }
  } // for (int i_i=0; i_i<t_tam; i_i++)
  //LOB for (StringObjectPair knownPropertyValue : knownPropertyValues)
  t_tam = knownPropertyValues!=null ? knownPropertyValues.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   if (knownPropertyValues[i_i].getString().equals( "propertyName" )) { //L if (knownPropertyValue.getString().equals( "propertyName" ) )
    propertyName = (String)knownPropertyValues[i_i].getObject(); //L (String)knownPropertyValue.getObject();
    break;
    }
   }
  if ((element instanceof edu.cmu.cs.stage3.alice.core.Variable) && ("value".equals( propertyName ))) {
   valueClass = ((edu.cmu.cs.stage3.alice.core.Variable)element).getValueClass();
  } else if ((element != null) && (propertyName != null)) {
   Class elementClass = element.getClass();
   if (element instanceof edu.cmu.cs.stage3.alice.core.Expression) {
    elementClass = ((edu.cmu.cs.stage3.alice.core.Expression)element).getValueClass();
    }
   valueClass = edu.cmu.cs.stage3.alice.core.Element.getValueClassForPropertyNamed( elementClass, propertyName );
   }

  return valueClass;
  }

 private static Class getValueClassForList( StringObjectPair[] knownPropertyValues) {
  Class valueClass = null;
  Object list = null;
  //LOB for (StringObjectPair knownPropertyValue : knownPropertyValues)
  int t_tam = knownPropertyValues!=null ? knownPropertyValues.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   if (knownPropertyValues[i_i].getString().equals( "list" )) { //L if (knownPropertyValue.getString().equals( "list" ) )
    list = knownPropertyValues[i_i].getObject(); //L list = knownPropertyValue.getObject();
    break;
    }
   }
  if (list instanceof edu.cmu.cs.stage3.alice.core.Variable) {
   edu.cmu.cs.stage3.alice.core.List realList = (edu.cmu.cs.stage3.alice.core.List)((edu.cmu.cs.stage3.alice.core.Variable)list).getValue();
   if (realList != null){
    valueClass = realList.valueClass.getClassValue();
    }
  } else if (list instanceof edu.cmu.cs.stage3.alice.core.List) {
   valueClass = ((edu.cmu.cs.stage3.alice.core.List)list).valueClass.getClassValue();
  } else { // bail
   valueClass = Object.class;
   }

  return valueClass;
  }

 private static Class getValueClassForArray( StringObjectPair[] knownPropertyValues) {
  Class valueClass = null;
  Object array = null;
  //LOB for (StringObjectPair knownPropertyValue : knownPropertyValues)
  int t_tam = knownPropertyValues!=null ? knownPropertyValues.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   if (knownPropertyValues[i_i].getString().equals( "array" )) { //L if (knownPropertyValue.getString().equals( "array" ) )
    array = knownPropertyValues[i_i].getObject(); //L array = knownPropertyValue.getObject();
    break;
    }
   }

  if (array instanceof edu.cmu.cs.stage3.alice.core.Variable) {
   edu.cmu.cs.stage3.alice.core.Array realArray = (edu.cmu.cs.stage3.alice.core.Array)((edu.cmu.cs.stage3.alice.core.Variable)array).getValue();
   valueClass = realArray.valueClass.getClassValue();
  } else if (array instanceof edu.cmu.cs.stage3.alice.core.Array) {
   valueClass = ((edu.cmu.cs.stage3.alice.core.Array)array).valueClass.getClassValue();
  } else { // bail
   valueClass = Object.class;
   }

  return valueClass;
  }

 private static Class generalizeValueClass(Class valueClass){
  Class newValueClass = valueClass;
  if (java.lang.Number.class.isAssignableFrom(valueClass)){
   newValueClass = java.lang.Number.class;
  } else if (edu.cmu.cs.stage3.alice.core.Model.class.isAssignableFrom(valueClass)){
   newValueClass = edu.cmu.cs.stage3.alice.core.Model.class;
   }
  return newValueClass;
  }

 private static Class getValueClassForComparator(StringObjectPair[] knownPropertyValues){
  Class valueClass = null;
  Object operand = null;
  //LOB for (StringObjectPair knownPropertyValue : knownPropertyValues)
  int t_tam = knownPropertyValues!=null ? knownPropertyValues.length : 0;
  for (int i_i=0; i_i<t_tam; i_i++) {
   if (knownPropertyValues[i_i].getString().equals( "a" )) { //L if (knownPropertyValue.getString().equals( "a" ) )
    operand = knownPropertyValues[i_i].getObject(); //L operand = knownPropertyValue.getObject();
    break;
    }
   }
  if (operand instanceof edu.cmu.cs.stage3.alice.core.Expression) {
   valueClass = ((edu.cmu.cs.stage3.alice.core.Expression)operand).getValueClass();
  } else if (operand != null) {
   valueClass = operand.getClass();
  } 
  return generalizeValueClass(valueClass);
  }

 public static Class getDesiredValueClass(edu.cmu.cs.stage3.alice.core.Property property){
  Class targetValueClass = property.getValueClass();
  if ((property.getOwner() instanceof edu.cmu.cs.stage3.alice.core.question.BinaryObjectResultingInBooleanQuestion) && (property.getName().equals( "a" ) || property.getName().equals( "b" ))) {
   Object otherValue;
   Object ourValue;
   if (property.getName().equals( "a" )) {
    otherValue = ((edu.cmu.cs.stage3.alice.core.question.BinaryObjectResultingInBooleanQuestion)property.getOwner()).b.get();
    ourValue = ((edu.cmu.cs.stage3.alice.core.question.BinaryObjectResultingInBooleanQuestion)property.getOwner()).a.get();
   } else {
    otherValue = ((edu.cmu.cs.stage3.alice.core.question.BinaryObjectResultingInBooleanQuestion)property.getOwner()).a.get();
    ourValue = ((edu.cmu.cs.stage3.alice.core.question.BinaryObjectResultingInBooleanQuestion)property.getOwner()).b.get();
    }
   Class otherValueClass;
   if (otherValue instanceof edu.cmu.cs.stage3.alice.core.Expression) {
    otherValueClass = ((edu.cmu.cs.stage3.alice.core.Expression)otherValue).getValueClass();
   } else if (otherValue != null) {
    otherValueClass = otherValue.getClass();
   } else {
    otherValueClass = property.getValueClass();
    }
   if (ourValue instanceof edu.cmu.cs.stage3.alice.core.Expression) {
    targetValueClass = ((edu.cmu.cs.stage3.alice.core.Expression)ourValue).getValueClass();
   } else if (ourValue != null) {
    targetValueClass = ourValue.getClass();
   } else {
    targetValueClass = property.getValueClass();
    }
   if (targetValueClass != otherValueClass){
    targetValueClass = otherValueClass;
    }
   targetValueClass = generalizeValueClass(targetValueClass);
   }
  return targetValueClass;
  }

 public static java.util.Vector makeDefaultOneShotStructure( edu.cmu.cs.stage3.alice.core.Element element) {
  return makeResponseStructure( element, oneShotFactory, element.getRoot() );
  }

 public static void ensurePopupIsOnScreen (JPopupMenu popup) {
  java.awt.Point location = popup.getLocation( null );
  java.awt.Dimension size = popup.getSize( null );
  java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
  screenSize.height -= 28; // hack for standard Windows Task Bar

  javax.swing.SwingUtilities.convertPointToScreen( location, popup );

  if (location.x < 0) {
   location.x = 0;
  } else if (location.x + size.width > screenSize.width) {
   location.x -= (location.x + size.width) - screenSize.width;
   }
  if (location.y < 0) {
   location.y = 0;
  } else if (location.y + size.height > screenSize.height) {
   location.y -= (location.y + size.height) - screenSize.height;
   }

  popup.setLocation( location );
  } // public static void ensurePopupIsOnScreen (JPopupMenu popup)
 }

// class PopupMenuItemActionListener implements java.awt.event.ActionListener
class PopupMenuItemActionListener implements java.awt.event.ActionListener {
 protected Runnable runnable;
 protected javax.swing.JMenu menu; //MEMFIX

 public PopupMenuItemActionListener( Runnable runnable) {
  this.runnable = runnable;
  }

 public PopupMenuItemActionListener( Runnable runnable, javax.swing.JMenu menu) { //MEMFIX
  this.runnable = runnable;
  this.menu = menu;
  }

 public void actionPerformed( java.awt.event.ActionEvent e) {
  try {
   runnable.run();
   if (menu != null) { //MEMFIX
    menu.getPopupMenu().setInvoker( null ); //MEMFIX
     }
   //runnable = null; //MEMFIX
  } catch( Throwable t) {
   AuthoringTool.getInstance().showErrorDialog( "Error encountered while responding to popup menu item.", t );
   }
  }

 } // class PopupMenuItemActionListener implements java.awt.event.ActionListener
